package service

import (
	"errors"
	"gdmin/db"
	"gdmin/global"
	"gdmin/model"
	"gdmin/servlet"
	"gdmin/utils"
	"gorm.io/gorm"
	"strconv"
)

type ResService struct {
}

func (s ResService) QueryButtonById(id int) *model.ResButton {
	var res model.ResButton
	global.DB.First(&res, id).Find(&res)
	return &res
}

func (s ResService) QueryMenuById(id int) *servlet.ResMenuResp {
	var res servlet.ResMenuResp

	global.DB.First(&res, id).Find(&res)

	if res.Id > 0 {
		if res.Pid > 0 {

			name := s.queryMenuNameById(res.Pid)

			res.ParentMenuName = name
		}

		res.BindApiIds = queryBindApiIds(res.Id)
		res.BindBtnIds = queryBindBtnIds(res.Id)

		res.BindApi = queryApiWithIds(res.BindApiIds)
		res.BindButton = queryBtnWithIds(res.BindBtnIds)
	}
	return &res
}

func queryBtnWithIds(ids []int) []model.ResButton {
	var d []model.ResButton

	global.DB.Model(&model.ResButton{}).Where("id in ? ", ids).Find(&d)

	return d
}

func queryApiWithIds(ids []int) []model.ResApi {
	var d []model.ResApi

	global.DB.Model(&model.ResApi{}).Where("id in ? ", ids).Find(&d)

	return d
}

func queryBindBtnIds(menuId int) []int {
	var res []int
	global.DB.Model(&model.ResButton{}).Where("menu_id =?", menuId).Select("id").Find(&res)
	return res
}

func queryBindApiIds(menuId int) []int {

	var res []int
	global.DB.Model(&model.MenuBindApi{}).Where("menu_id =?", menuId).Select("res_api_id").Find(&res)
	return res

}

func (s ResService) QueryApiById(id int) *model.ResApi {
	var res model.ResApi
	global.DB.First(&res, id).Find(&res)
	return &res
}

func (s ResService) MenuBindApi(req *servlet.CreateMenuBindApi) error {

	return global.DB.Transaction(func(tx *gorm.DB) error {

		var dels []*model.MenuBindApi
		tx.Model(&model.MenuBindApi{}).Where("menu_id = ?", req.MenuId).Find(&dels)
		for _, item := range dels {
			item.UpdateUserId = utils.GetThreadUserId()
			item.IsDel = 1
		}
		if len(dels) > 0 {

			err := tx.Save(&dels).Error
			if err != nil {
				return err
			}
		}
		for _, v := range req.ApiIds {
			var menuBindApi model.MenuBindApi
			menuBindApi.MenuId = req.MenuId
			menuBindApi.ResApiId = v
			err := tx.Create(&menuBindApi).Error
			if err != nil {
				return err
			}
		}
		return nil

	})

}

func (s ResService) UpdateApi(req *servlet.UpdateResApiReq) (*model.ResApi, error) {

	if req.Id < 0 {
		return nil, errors.New("id不能为空")
	}
	if req.Path == "" {

		return nil, errors.New("路径不能为空")
	}
	if req.Name == "" {

		return nil, errors.New("名称不能为空")
	}
	if req.Method == "" {

		return nil, errors.New("请求方式不能为空")
	}

	var old model.ResApi
	err := global.DB.First(&old, req.Id).Error
	if err != nil {
		return nil, err
	} else {

		err := checkMethodPathNameRequired(req.Path, req.Method, req.Name, req.Id)
		if err != nil {
			return nil, err
		}
		old.Name = req.Name
		old.Path = req.Path
		old.Method = req.Method

		err = global.DB.Transaction(func(tx *gorm.DB) error {
			return tx.Save(&old).Error
		})
		if err != nil {
			return nil, err
		} else {

			return &old, nil

		}

	}

}

func checkMethodPathNameRequired(path string, method string, name string, id int) error {
	dbobj := model.ResApi{}
	err := global.DB.Where("path =? and method = ? and name = ? ", path, method, name).First(&dbobj).Error

	if err == nil {
		if dbobj.Id == 0 {
			return nil
		}
		if dbobj.Id != id {
			return errors.New("存在重复数据")

		}
	} else {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
	}

	return err
}

func (s ResService) CreateApi(req *servlet.CreateResApiReq) (*model.ResApi, error) {
	if req.Path == "" {

		return nil, errors.New("路径不能为空")
	}
	if req.Name == "" {

		return nil, errors.New("名称不能为空")
	}
	if req.Method == "" {

		return nil, errors.New("请求方式不能为空")
	}

	var db model.ResApi
	err := checkMethodPathNameRequired(req.Path, req.Method, req.Name, -1)
	if err != nil {
		return nil, err
	}
	db.Name = req.Name
	db.Path = req.Path
	db.Method = req.Method

	err = global.DB.Transaction(func(tx *gorm.DB) error {
		return tx.Save(&db).Error
	})
	if err != nil {
		return nil, err
	} else {

		return &db, nil

	}

}

func (s ResService) UpdateMenu(req *servlet.UpdateResMenuReq) (*model.ResMenu, error) {

	if req.Id < 0 {
		return nil, errors.New("id不能为空")
	}

	if req.Name == "" {
		return nil, errors.New("名称不能为空")
	}
	if req.Path == "" {
		return nil, errors.New("路径不能为空")
	}
	//if req.Icon == "" {
	//	return nil, errors.New("图标不能为空")
	//}
	var old model.ResMenu
	err := global.DB.First(&old, req.Id).Error
	if err != nil {
		return nil, err
	} else {

		old.Name = req.Name
		old.Path = req.Path
		old.Icon = req.Icon
		old.Pid = req.Pid

		err = global.DB.Transaction(func(tx *gorm.DB) error {
			return tx.Save(&old).Error
		})
		if err != nil {
			return nil, err
		} else {

			return &old, nil

		}

	}

}

func (s ResService) CreateMenu(req *servlet.CreateResMenuReq) (*model.ResMenu, error) {

	if req.Name == "" {
		return nil, errors.New("名称不能为空")
	}
	if req.Path == "" {
		return nil, errors.New("路径不能为空")
	}
	//if req.Icon == "" {
	//	return nil, errors.New("图标不能为空")
	//}

	var old model.ResMenu
	old.Name = req.Name
	old.Path = req.Path
	old.Icon = req.Icon
	old.Pid = req.Pid

	err := global.DB.Transaction(func(tx *gorm.DB) error {
		return tx.Save(&old).Error
	})
	if err != nil {
		return nil, err
	} else {

		return &old, nil

	}

}

func (s ResService) UpdateButton(req *servlet.UpdateResButtonReq) (*model.ResButton, error) {
	if req.Id < 0 {
		return nil, errors.New("id不能为空")
	}
	if req.Name == "" {
		return nil, errors.New("名称不能为空")
	}
	if req.Uid == "" {
		return nil, errors.New("唯一标识不能为空")
	}
	if req.MenuId > 0 {
		return nil, errors.New("菜单id不能为空")
	}

	var old model.ResButton

	err := global.DB.First(&old, req.Id).Error
	if err != nil {
		return nil, err
	} else {
		old.Name = req.Name
		old.Uid = req.Uid
		old.MenuId = req.MenuId

		err := global.DB.Transaction(func(tx *gorm.DB) error {
			return tx.Save(&old).Error
		})
		if err != nil {
			return nil, err
		} else {

			return &old, nil

		}
	}
}

func (s ResService) CreateButton(req *servlet.CreateResButtonReq) (*model.ResButton, error) {

	if req.Name == "" {
		return nil, errors.New("名称不能为空")
	}
	if req.Uid == "" {
		return nil, errors.New("唯一标识不能为空")
	}
	if req.MenuId < 0 {
		return nil, errors.New("菜单id不能为空")
	}

	var old model.ResButton
	old.Name = req.Name
	old.Uid = req.Uid
	old.MenuId = req.MenuId

	err := global.DB.Transaction(func(tx *gorm.DB) error {
		return tx.Save(&old).Error
	})
	if err != nil {
		return nil, err
	} else {

		return &old, nil

	}

}

func (s ResService) PageResButton(req *servlet.QueryResButton) interface{} {
	var d []*servlet.ResButtonResp

	query := global.DB.Model(&d)
	if req.Name != "" {
		query.Where("name like ? ", "%"+req.Name+"%")
	}
	if req.MenuId > 0 {
		query.Where("menu_id =? ", req.MenuId)
	}
	if req.Code != "" {
		query.Where("code  like ? ", "%"+req.Code+"%")
	}

	page := db.CommonPage(&req.Pagination, &d, query)

	return page
}

func (s ResService) PageResMenu(req *servlet.QueryResMenu) interface{} {
	var d []*servlet.ResMenuResp

	query := global.DB.Model(&d)
	if req.Name != "" {
		query.Where("name like ? ", "%"+req.Name+"%")
	}

	if req.Pid > 0 {
		query.Where("pid = ? ", req.Pid)

	}
	if req.Path != "" {
		query.Where("path  like ? ", "%"+req.Path+"%")
	}
	if req.Icon != "" {
		query.Where("icon =? ", req.Icon)
	}

	page := db.CommonPage(&req.Pagination, &d, query)
	for _, v := range d {
		v.ParentMenuName = s.queryMenuNameById(v.Pid)
	}
	return page
}

func (s ResService) PageResApi(req *servlet.QueryResApi) interface{} {
	var d []*servlet.ResApiResp

	query := global.DB.Model(&d)
	if req.Name != "" {
		query.Where("name like ? ", "%"+req.Name+"%")
	}

	page := db.CommonPage(&req.Pagination, &d, query)

	return page
}

func (s ResService) queryMenuNameById(pid int) string {
	dest := &model.ResMenu{}
	global.DB.Where("id =? ", pid).First(dest)
	return dest.Name

}

func (s ResService) DeleteResButtonById(param string) {
	global.DB.Where("id =?", param).Delete(&model.ResButton{})

}

func (s ResService) DeleteResMenuById(param string) {
	global.DB.Where("id =?", param).Delete(&model.ResMenu{})

}

func (s ResService) DeleteResApiById(param string) {
	global.DB.Where("id =?", param).Delete(&model.ResApi{})

}

func (s ResService) MenuTree(param string) ([]model.NodeWithChildren, error) {
	if param != "" {

		atoi, err := strconv.Atoi(param)
		if err != nil {
			return nil, err
		}

		return s.menuTree(atoi), nil
	} else {
		return s.menuTree(-1), nil
	}
}

func (s ResService) menuTree(pid int) []model.NodeWithChildren {
	var mts []model.ResMenu

	if pid > 0 {
		global.DB.Where("pid =?", pid).Find(&mts)
	} else {
		err := global.DB.Model(&model.ResMenu{}).Find(&mts).Error
		if err != nil {
			panic(err)
		}
	}

	menu := model.ResMenu{}
	tree := menu.MakeTree(mts)

	return tree
}

func (s ResService) ListApi() *[]model.ResApi {
	var api []model.ResApi
	global.DB.Model(&api).Find(&api)
	return &api
}

func (s ResService) FindMenuByRoleIds(roleIds []int) []model.ResMenu {
	var db []int
	global.DB.Model(&model.RoleBindMenu{}).Where("role_id in (?)", roleIds).Select("menu_id").Find(&db)
	var menu []model.ResMenu
	global.DB.Model(&model.ResMenu{}).Where("id in (?)", db).Find(&menu)

	//todo: 2023年12月18日
	//  查询下级放入到集合中
	return menu
}
